package com.jxjk.reportwork.biz;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.jxjk.reportwork.ReportStatusEnum;
import com.jxjk.reportwork.exceldo.RealReportDetailInExcelDO;
import com.jxjk.reportwork.exceldo.ReportErrorOutExcelDO;
import com.jxjk.reportwork.exceldo.ReportPlanInExcelDO;
import com.jxjk.reportwork.listener.RealReportPlanListener;
import com.jxjk.reportwork.listener.ReportPlanListener;
import com.jxjk.reportwork.model.ReportConfig;
import com.jxjk.reportwork.model.ReportPlanDetail;
import com.jxjk.reportwork.util.DateUtils;
import com.jxjk.reportwork.util.ReportWorkConstant;
import com.jxjk.reportwork.util.StringFormatUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Session;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * 报工对账只需要两个文件：
 * 1. 报工计划表
 * 2. 实际报工明细表
 * 3. 不需要出差明细表
 */
@Slf4j
@Data
public class WorkReportBiz {
    private List<RealReportDetailInExcelDO> realReportDetailInExcelDOList = Lists.newArrayList();
    private List<ReportPlanInExcelDO> reportPlanInExcelDOList = Lists.newArrayList();
    private ReportConfig reportConfig;
    private Session session;

    /**
     * 加载excel，包括：报工计划，实际报工明细两个excel表格
     */
    public void loadExcel() {
        ReportPlanListener reportPlanListener = new ReportPlanListener();
        String reportPlanFileName = ReportWorkConstant.WORK_DIR + reportConfig.getReportPlanFile();
        log.info("替换后的文件名称, reportPlanFileName: {}", reportPlanFileName);

        File reportPlanFile = new File(reportPlanFileName);
        //2024.9.23: 遇到了灵异事件, 用sheetName可以读取到excel表格的内容
        EasyExcel.read(reportPlanFile, ReportPlanInExcelDO.class, reportPlanListener).sheet("报工安排").doRead();
        this.reportPlanInExcelDOList.addAll(reportPlanListener.getReportPlanInExcelDOList());

        RealReportPlanListener realReportPlanListener = new RealReportPlanListener();
        String realReportPlanFileName = ReportWorkConstant.WORK_DIR + reportConfig.getRealReportFile();
        log.info("替换后的文件名称, realReportPlanFileName: {}", realReportPlanFileName);
        File realReportPlanFile = new File(realReportPlanFileName);
        EasyExcel.read(realReportPlanFile, RealReportDetailInExcelDO.class, realReportPlanListener).sheet(0).doRead();
        this.realReportDetailInExcelDOList.addAll(realReportPlanListener.getRealReportDetailInExcelDOList());
    }

    /**
     * 报工对账，找出差异(多帐、少帐)
     * <p>
     * 根据报工计划、报工明细，找出报工差异，有哪些是多余的报工，有哪些是缺少的报工
     */
    public void handleWorkReport() {

        log.info("reportConfig:{}", reportConfig);
        //第1步：保存报工计划
        List<ReportPlanDetail> reportPlanDetailList = Lists.newArrayList();
        for (ReportPlanInExcelDO reportPlanInExcelDO : this.reportPlanInExcelDOList) {
            for (Date tmpDate : reportConfig.getWorkDateList()) {
                ReportPlanDetail reportPlanDetail = new ReportPlanDetail();
                reportPlanDetail.setReportDate(tmpDate);
                reportPlanDetail.setProjectName(reportPlanInExcelDO.getProjectName());
                reportPlanDetail.setReportDepartment(reportPlanInExcelDO.getReportDepartment());
                reportPlanDetail.setDepartment(reportPlanInExcelDO.getDepartment());
                reportPlanDetail.setStaffName(reportPlanInExcelDO.getStaffName());
                reportPlanDetail.setStaffNo(reportPlanInExcelDO.getStaffNo());

                //如果该员工报工的团队是云平台研发团队，则保存到报工计划里
                if (StringUtils.equalsIgnoreCase(reportPlanDetail.getReportDepartment(), "云平台研发团队")) {
                    session.save(reportPlanDetail);
                    log.info("报工计划: {}", reportPlanDetail);
                    reportPlanDetailList.add(reportPlanDetail);
                }
            }
        }

        //第2步：保存实际报工明细
        for (RealReportDetailInExcelDO realReportDetailInExcelDO : this.realReportDetailInExcelDOList) {
            session.save(realReportDetailInExcelDO);
        }

        //第3步：得到多余的报工
        List<ReportErrorOutExcelDO> redundantReportErrorOutExcelDOList = Lists.newArrayList();
        for (RealReportDetailInExcelDO realReportDetailInExcelDO : this.realReportDetailInExcelDOList) {
            ReportPlanDetail tmpDetail = (ReportPlanDetail) session.createQuery(
                    " from ReportPlanDetail where staffNo = :staffNo and reportDate = :reportDate")
                    .setString("staffNo", realReportDetailInExcelDO.getStaffNo())
                    .setDate("reportDate", realReportDetailInExcelDO.getReportDate())
                    .uniqueResult();
            if (StringUtils.equalsIgnoreCase(realReportDetailInExcelDO.getReportStatus(), ReportStatusEnum.PASS.getName()) == false) {
                continue;
            }
            if (tmpDetail == null) {
                log.info("realReportDetailInExcelDO:{}", realReportDetailInExcelDO);
                ReportErrorOutExcelDO reportErrorOutExcelDO = new ReportErrorOutExcelDO();
                reportErrorOutExcelDO.setStaffName(realReportDetailInExcelDO.getStaffName());
                reportErrorOutExcelDO.setStaffNo(realReportDetailInExcelDO.getStaffNo());
                reportErrorOutExcelDO.setReportDate(realReportDetailInExcelDO.getReportDate());
                reportErrorOutExcelDO.setReportHour(realReportDetailInExcelDO.getReportHour());
                reportErrorOutExcelDO.setPlanProjectName(realReportDetailInExcelDO.getProjectName());
                reportErrorOutExcelDO.setReason("多余的报工");
                redundantReportErrorOutExcelDOList.add(reportErrorOutExcelDO);
                continue;
            } else if ((StringUtils.indexOf(realReportDetailInExcelDO.getFinanceName(), tmpDetail.getProjectName()) >= 0
                    || StringUtils.indexOf(tmpDetail.getProjectName(), realReportDetailInExcelDO.getFinanceName()) >= 0) == false) {
                //2024.9.25: 调整了项目名称匹配方式，只要两个名称中有重复的内容，则认为项目名称一致
                //2024.9.25: 这帮人经常乱取项目名称，导致项目名称极其混乱
                ReportErrorOutExcelDO reportErrorOutExcelDO = new ReportErrorOutExcelDO();
                reportErrorOutExcelDO.setStaffName(realReportDetailInExcelDO.getStaffName());
                reportErrorOutExcelDO.setStaffNo(realReportDetailInExcelDO.getStaffNo());
                reportErrorOutExcelDO.setReportDate(realReportDetailInExcelDO.getReportDate());
                reportErrorOutExcelDO.setReportHour(realReportDetailInExcelDO.getReportHour());
                reportErrorOutExcelDO.setPlanProjectName(tmpDetail.getProjectName());
                reportErrorOutExcelDO.setRealProjectName(realReportDetailInExcelDO.getProjectName());
                reportErrorOutExcelDO.setReason("报工项目不对，应该报工项目");
                redundantReportErrorOutExcelDOList.add(reportErrorOutExcelDO);
            } else if (realReportDetailInExcelDO.getReportHour() < 8) {
                ReportErrorOutExcelDO reportErrorOutExcelDO = new ReportErrorOutExcelDO();
                reportErrorOutExcelDO.setStaffName(realReportDetailInExcelDO.getStaffName());
                reportErrorOutExcelDO.setStaffNo(realReportDetailInExcelDO.getStaffNo());
                reportErrorOutExcelDO.setReportDate(realReportDetailInExcelDO.getReportDate());
                reportErrorOutExcelDO.setReportHour(realReportDetailInExcelDO.getReportHour());
                reportErrorOutExcelDO.setPlanProjectName(tmpDetail.getProjectName());
                reportErrorOutExcelDO.setRealProjectName(realReportDetailInExcelDO.getProjectName());
                reportErrorOutExcelDO.setReason("当日报工小于8个小时");
                redundantReportErrorOutExcelDOList.add(reportErrorOutExcelDO);
            }
        }

        //第4步：得到该报工而实际没有报工的记录
        List<ReportErrorOutExcelDO> lackReportErrorOutExcelDOList = Lists.newArrayList();
        for (ReportPlanDetail reportPlanDetail : reportPlanDetailList) {
            long count = (long) session.createQuery(
                    "select count(*) from RealReportDetailInExcelDO where staffNo = :staffNo and reportDate = :reportDate")
                    .setString("staffNo", reportPlanDetail.getStaffNo())
                    .setDate("reportDate", reportPlanDetail.getReportDate())
                    .uniqueResult();
            if (count == 0) {
                ReportErrorOutExcelDO reportErrorOutExcelDO = new ReportErrorOutExcelDO();
                reportErrorOutExcelDO.setStaffName(reportPlanDetail.getStaffName());
                reportErrorOutExcelDO.setStaffNo(reportPlanDetail.getStaffNo());
                reportErrorOutExcelDO.setReportDate(reportPlanDetail.getReportDate());
                reportErrorOutExcelDO.setPlanProjectName(reportPlanDetail.getProjectName());
                reportErrorOutExcelDO.setReason("当日没有报工");
                lackReportErrorOutExcelDOList.add(reportErrorOutExcelDO);
            }
        }

        //第5步：汇总多余的报工+缺少的报工
        List<ReportErrorOutExcelDO> reportErrorOutExcelDOList = Lists.newArrayList();
        reportErrorOutExcelDOList.addAll(redundantReportErrorOutExcelDOList);
        reportErrorOutExcelDOList.addAll(lackReportErrorOutExcelDOList);

        //第5步：写入对账结果excel文件
        String today = DateUtils.getDateString(new Date(), "yyyy-MM-dd");
        String resultFileName = StringFormatUtil.format(ReportWorkConstant.RESULT_FILE, today);
        String fullResultFileName = ReportWorkConstant.WORK_DIR + resultFileName;
        File resultFile = new File(fullResultFileName);
        if (resultFile.exists()) {
            resultFile.delete();
        }
        LongestMatchColumnWidthStyleStrategy styleStrategy = new LongestMatchColumnWidthStyleStrategy();
        EasyExcel.write(resultFile, ReportErrorOutExcelDO.class).registerWriteHandler(styleStrategy)
                .sheet("结果").doWrite(reportErrorOutExcelDOList);
    }

    /**
     * 2024.11.25日临时用一下
     */
    @Deprecated
    public void printStaffInfo() {
        List<String> staffNameList = readStaffFile();
        for (String staffName : staffNameList) {
            boolean matched = false;
            for (ReportPlanInExcelDO reportPlanInExcelDO : reportPlanInExcelDOList) {
                if (StringUtils.equalsIgnoreCase(staffName, reportPlanInExcelDO.getStaffName())) {
                    log.info("{}\t{}", reportPlanInExcelDO.getStaffName(), reportPlanInExcelDO.getStaffNo());
                    matched = true;
                }
            }
            if (matched == false) {
                log.info("{}\t{}", staffName, "");
            }
        }
    }

    public List<String> readStaffFile() {
        try {
            List<String> staffNameList = FileUtils.readLines(new File("D:\\workspace\\java\\gitlab\\20240122\\ReportWorkLocal\\src\\main\\resources\\staffName.txt"), "utf8");
            log.info("staffNameList.size:{}", staffNameList.size());
            return staffNameList;

        } catch (IOException e) {
            log.error("出现异常", e);
        }
        return Lists.newArrayList();
    }
}
